package com.jsyso.jsyso.spring;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.jsyso.jsyso.db.Db;
import com.jsyso.jsyso.db.Dialect;
import com.jsyso.jsyso.db.dialect.MySqlDialect;
import com.jsyso.jsyso.exception.DbException;

/**
 * Db工厂
 * @author janjan, xujian_jason@163.com
 *
 */
public class DbFactoryBean implements FactoryBean<Db>, InitializingBean {
	private static final Logger logger = LoggerFactory.getLogger(DbFactoryBean.class);
	
	// 数据库
	private Db db;
	// 主数据源（写库）
	private DataSource dataSource;
	// 备用数据源（读库）
	private DataSource[] slaveDataSources;
	// 是否启用读写分类
	private boolean rwSeparate;
	// debug模式
	private boolean debug;
	// 数据库方言
	private String type;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		this.db = this.buildDb();
	}
	
	private void pLog(String msg) {
		if(this.debug) {
			logger.debug(msg);
		}
	}
	
	protected Db buildDb() {
		// 数据库方言
		Dialect dialect = null;
		if(this.type == null || "mysql".equalsIgnoreCase(this.type)) {
			dialect = new MySqlDialect();
		}
		if(dialect == null) {
			dialect = new MySqlDialect();
		}
		this.pLog("[db build] dialect = " + this.type);
		
		// 主库
		NamedParameterJdbcOperations master = null;
		if(this.dataSource != null) {
			master = new NamedParameterJdbcTemplate(this.dataSource);
		}
		if(master == null) {
			throw new DbException("[db build error] dataSource == null");
		}
		
		// 读库集合
		NamedParameterJdbcOperations[] slaves = null;
		if(this.slaveDataSources != null 
				&& this.slaveDataSources.length > 0) {
			slaves = new NamedParameterJdbcOperations[this.slaveDataSources.length];
			int i=0, length = this.slaveDataSources.length;
			for(; i<length; ++i) {
				DataSource dataSource = this.slaveDataSources[i];
				slaves[i] = new NamedParameterJdbcTemplate(dataSource);
			}
			this.pLog("[db build] slaves.length = " + slaves.length);
		}
		
		// 构建Db
		Db db = new Db();
		db.setDebug(this.debug);
		db.setRwSeparate(this.rwSeparate && slaves != null && slaves.length > 0);
		db.setDialect(dialect);
		db.setMaster(master);
		db.setSlaves(slaves);
		
		return db;
	}

	@Override
	public Db getObject() throws Exception {
		if(this.db == null) {
			afterPropertiesSet();
		}
		return this.db;
	}

	@Override
	public Class<?> getObjectType() {
		return this.db == null ? Db.class : this.db.getClass();
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
	
	/**
	 * 设置主数据源（写库）
	 * @param dataSource
	 */
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	
	/**
	 * 设置备用数据源集合（读库）
	 * @param slaveDataSources
	 */
	public void setSlaveDataSources(DataSource[] slaveDataSources) {
		this.slaveDataSources = slaveDataSources;
	}

	/**
	 * 是否开启读写分类
	 * @param isRwSeparate
	 */
	public void setRwSeparate(boolean rwSeparate) {
		this.rwSeparate = rwSeparate;
	}

	/**
	 * 是否开启debug模式
	 * @param isDebug
	 */
	public void setDebug(boolean debug) {
		this.debug = debug;
	}

	/**
	 * 数据库类型
	 * @param type
	 */
	public void setType(String type) {
		this.type = type;
	}
}
